﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace LambdaGp.Core.Streaming
{
    public abstract class GenomeLoaderBase
    {
        private readonly GenomeDefinition _genomeDefinition;
        private readonly Regex _codeTokenizer;
        private IEnumerator<string> _tokenQueue;        

        protected GenomeLoaderBase(GenomeDefinition genomeDefinition, string tokenizerRegex)
        {
            _genomeDefinition = genomeDefinition;
            _codeTokenizer = new Regex(
                tokenizerRegex, 
                RegexOptions.Singleline);
        }

        public GenomeDefinition GenomeDefinition { get { return _genomeDefinition; } }

        public OperatorNode LoadFromString(string genome)
        {
            List<string> tokens = Tokensize(genome);
            _tokenQueue = tokens.GetEnumerator();

            OperatorNode node = new OperatorNode();

            LoadNodeFromTokenQueue(node);

            if (_tokenQueue.MoveNext())
            {
                throw new InvalidOperationException(
                    string.Format(
                        "There are more tokens to be processed: {0}", 
                        _tokenQueue.Current));
            }

            return node;
        }

        protected List<string> Tokensize(string genome)
        {
            Match matchResults = _codeTokenizer.Match(genome);
            List<string> tokens = new List<string>();
            while (matchResults.Success)
            {
                if (matchResults.Value.Trim() != string.Empty)
                {
                    tokens.Add(matchResults.Value);
                }

                matchResults = matchResults.NextMatch();
            }

            return tokens;
        }

        protected string GetNextToken()
        {
            if (_tokenQueue.MoveNext() == false)
            {
                throw new InvalidOperationException("Ran out of tokens!");
            }

            return _tokenQueue.Current;
        }

        protected abstract void LoadNodeFromTokenQueue(OperatorNode node);
    }
}
